﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once

#include "ICurve2d.h"

namespace gcmp
{
    /// \brief 二维NURBS曲线
    ///
    class INurbsCurve2d : public ICurve2d
    {
        DEFINE_CAST_DERIVED(gcmp::INurbsCurve2d, gcmp::ICurve2d);
    public:
        /// \brief 根据控制顶点和节点矢量来创建一般NURBS曲线
        /// \param degree 曲线次数
        /// \param controlPoints 控制顶点数组
        /// \param weights 各控制顶点的权值数组，长度应与控制顶点个数相同
        /// \param knotVector 节点矢量，长度应等于：次数+控制顶点个数+1
        /// \return 二维NURBS曲线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<INurbsCurve2d> Create(int degree, const std::vector<Vector2d>& controlPoints,
            const std::vector<double>& weights, const std::vector<double>& knotVector);

        /// \brief 根据控制顶点来创建一般NURBS曲线，自动计算节点矢量，并设置各控制顶点的权值为1
        /// \param degree 曲线次数
        /// \param controlPoints 控制顶点数组
        /// \return 二维NURBS曲线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<INurbsCurve2d> Create(int degree, const std::vector<Vector2d>& controlPoints);

        /// \brief 根据插值点来创建一般NURBS曲线
        /// \param throughPoints 插值点数组
        /// \return 二维NURBS曲线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<INurbsCurve2d> Create(const std::vector<Vector2d>& throughPoints);

        /// \brief 通过控制顶点构造指定次数的二维周期型样条曲线。
        /// 
        /// 注意：因为周期型曲线得到的控制点数不满足“节点矢量数=次数+控制点数+1”这一特征，所以通过周期型曲线得到的控制点和节点矢量数据来创建一般NURBS曲线时不能保证成功。
        /// \param degree 曲线次数
        /// \param controlPoints 控制顶点集合，用户保证控制点数（首末去重之后的数量）大于次数
        /// \return 二维周期型样条曲线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<INurbsCurve2d> CreatePeriodicNurbsCurve2d(int degree, std::vector<Vector2d>& controlPoints);

        /// \brief 通过插值点构造三次的二维周期型样条曲线。
        /// 
        /// 注意：因为周期型曲线得到的控制点数不满足“节点矢量数=次数+控制点数+1”这一特征，所以通过周期型曲线得到的控制点和节点矢量数据来创建一般NURBS曲线时不能保证成功。
        /// \param throughPoints 插值点集合,用户保证非重插值点数大于1
        /// \return 二维周期型样条曲线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<INurbsCurve2d> CreatePeriodicNurbsCurve2d(const std::vector<Vector2d>& throughPoints);

    public:
        /// \brief 获得NURBS曲线次数
        /// \return NURBS曲线次数
        virtual int GetDegree() const = 0;

        /// \brief 获得NURBS曲线控制顶点
        /// \param controlPoints NURBS曲线控制顶点数组
        /// \return 无
        virtual void GetControlPoints(std::vector<Vector2d>& controlPoints) const = 0;

        /// \brief 设置NURBS曲线控制顶点及其权值
        /// \param index 控制顶点序号
        /// \param newControlPoint 控制顶点位置
        /// \param weight 权值
        /// \return true
        virtual void SetControlPoint(int index, const Vector2d& newControlPoint, double weight) = 0;

        /// \brief 获得NURBS曲线控制顶点个数
        /// \return 控制顶点个数
        virtual int GetControlPointCount() const = 0;

        /// \brief 获得NURBS曲线控制顶点权值
        /// \param weights NURBS曲线权值数组
        /// \return 无
        virtual void GetWeights(std::vector<double>& weights) const = 0;

        /// \brief 获得NURBS曲线节点矢量
        /// \param knotVector NURBS曲线节点矢量
        /// \return 无
        virtual void GetKnotVector(std::vector<double>& knotVector) const = 0;

        /// \brief 判断样条曲线是否周期型。
        /// 
        /// 注意：此方法与ICurve::IsPeriodic()不同。
        /// ICurve::IsPeriodic()是判断一般曲线是否周期型，只要求闭合以及range可以按闭合周期延续即可。
        /// 而此处INurbsCurve2d::IsPeriodicNurbsCurve2d()是针对样条曲线进行判断是否周期型。
        /// 周期型样条曲线除了ICurve::IsPeriodic()满足周期型的条件外，还需要控制点和节点矢量的节点值也能按周期延续，属于特殊情况特殊判断。
        /// \return 如果是周期型则返回true；否则返回false。
        virtual bool IsPeriodicNurbsCurve2d() const = 0;


    public:
        virtual ~INurbsCurve2d() {}
    };
}

